﻿using System;
using System.Collections.Generic;
using Type = System.Type;
using UnityEngine;
using System.Collections;

namespace ScFramework.Core
{
    /// <summary>
    /// 流程管理，管理整个软件使用流程，以及流程之间的切换。
    /// </summary>
    public class ProcedureManager : SystemModule
    {
        /// <summary>
        /// 获取当前流程。
        /// </summary>
        public ProcedureBase Current
        {
            get
            {
                return _current;
            }
        }

        /// <summary>
        /// 获取上一个流程。
        /// </summary>
        public ProcedureBase Previous
        {
            get
            {
                return _previous;
            }
        }

        /// <summary>
        /// 当前的流程。
        /// </summary>
        private ProcedureBase _current;

        /// <summary>
        /// 上一个流程。
        /// </summary>
        private ProcedureBase _previous;

        private readonly Dictionary<Type, ProcedureBase> _procedureDictionary = new Dictionary<Type, ProcedureBase>();

        /// <summary>
        /// 初始化函数，实例化所有流程并完成初始化。
        /// </summary>
        public override void Initialize(Main m)
        {
            base.Initialize(m);
        //获取所有流程名称
        string[] procedures = Utilities.TypeUtilities.GetTypeNames(typeof(ProcedureBase));

            //实例化所有流程对象
            for (int i = 0; i < procedures.Length; i++)
            {
                Type t = Type.GetType(procedures[i]);
                ProcedureBase pb = Activator.CreateInstance(t) as ProcedureBase;
                _procedureDictionary[t] = pb;

                //执行初始化函数
                pb.Init(_main);
            }
        }

        /// <summary>
        /// 将流程切换至另一个流程。
        /// </summary>
        /// <typeparam name="T">流程类型。</typeparam>
        public void ChangeTo<T>(List<string>submoduleList=null,object args = null) where T : ProcedureBase
        {
            //切换至下一个流程
            ChangeTo(_procedureDictionary[typeof(T)],null, args);
        }

        /// <summary>
        /// 将流程切换至另一个流程。
        /// </summary>
        /// <param name="name">流程名。</param>
        public void ChangeTo(string name, object args = null)
        {
            try
            {
                string[] list = DataUtil.Table.GetStrings("ProcedureSetting",
                    name, "SubmoduleList"
                    );
                string type=DataUtil.Table.GetString("ProcedureSetting",
                    name, "ProcedureType"
                    );

                var nlist = new List<string>(list);
                nlist.RemoveAll(s => string.IsNullOrWhiteSpace(s));
                foreach (KeyValuePair<Type, ProcedureBase> pair in _procedureDictionary)
            {
                if (pair.Key.Name == type)
                {
                    //切换至下一个流程
                    ChangeTo(_procedureDictionary[pair.Key],nlist, args);
                    return;
                }
            }
            }
            catch(KeyNotFoundException e)
            {
                Debug.LogError("流程切换的参数有误"+e);
                throw e;
            }
            //没有找到则抛出异常
            throw new ArgumentException();
        }

        /// <summary>
        /// 将流程切换至另一个流程。
        /// </summary>
        /// <param name="pb">流程对象。</param>
        public void ChangeTo(ProcedureBase pb,List<string>submoduleList=null, object args = null)
        {
            if (OnChangeTo)
            {
                return;
            }
            OnChangeTo = true;
            _main.StartCoroutine(WaitSeconds(pb,submoduleList, args));
            return;
        }
        private bool OnChangeTo = false;
        private IEnumerator WaitSeconds(ProcedureBase pb, List<string> submoduleList, object args)
        {
            if (_current != null)
            {
                 _current.LeaveAnimation();
                yield return new WaitForSeconds(_current.LeaveAnimationTime);
                _current.EnterLeaveAnimationClose();
            }

            OnChangeTo = false;
            //do load animation

            if (_current != null)
            {
                    _current.Leave();
                ObjectPool.DestroyAllPooled();
            }

            //保存上一个流程
            _previous = _current;

            if (_procedureDictionary.ContainsValue(pb))
            {
                //切换至下一个流程
                _current = pb;

                //执行进入函数
                pb.Enter(submoduleList,args);
                _current.EnterAnimation();
                yield return new WaitForSeconds(_current.EnterAnimationTime);

                _current.EnterLeaveAnimationClose();

            }
            else
            {
                //该流程不是默认创建的流程，抛出异常
                throw new ArgumentException();
            }
            //finish load animation
        }
        /// <summary>
        /// 更新流程。
        /// </summary>
        /// <param name="elapseSeconds">流逝时间，以秒为单位。</param>
        public override void SysUpdate(float elapseSeconds)
        {
            if (_current != null)
            {
                _current.Update(elapseSeconds);
            }
        }

        public override void SysLateUpdate(float elapseSeconds)
        {
            if (_current != null)
            {
                _current.LateUpdate(elapseSeconds);
            }
        }

        /// <summary>
        /// 物理更新流程。
        /// </summary>
        /// <param name="elapseSeconds">流逝时间，以秒为单位。</param>
        public override void SysFixedUpdate(float elapseSeconds)
        {
            if (_current != null)
            {
                _current.FixedUpdate(elapseSeconds);
            }
        }

        public override void SysLateFixedUpdate()
        {
            base.SysLateFixedUpdate();
            if (_current != null)
            {
                _current.LateFixedUpdate();
            }
        }

        /// <summary>
        /// 退出时执行。
        /// </summary>
        public override void Dispose()
        {
            if (_current != null)
            {
            //    _current.Leave();
                _current = null;
            }
            foreach (KeyValuePair<Type, ProcedureBase> pair in _procedureDictionary)
            {
                pair.Value.Destroy();
            }
        }
    }
}